package com.yuma.tingshu.payment.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.yuma.tingshu.account.client.RechargeInfoFeignClient;
import com.yuma.tingshu.common.constant.SystemConstant;
import com.yuma.tingshu.common.execption.YumaException;
import com.yuma.tingshu.common.result.Result;
import com.yuma.tingshu.common.result.ResultCodeEnum;
import com.yuma.tingshu.common.util.AuthContextHolder;
import com.yuma.tingshu.model.account.RechargeInfo;
import com.yuma.tingshu.model.order.OrderInfo;
import com.yuma.tingshu.model.payment.PaymentInfo;
import com.yuma.tingshu.model.user.UserInfo;
import com.yuma.tingshu.order.client.OrderInfoFeignClient;
import com.yuma.tingshu.payment.config.WxPayProperties;
import com.yuma.tingshu.payment.mapper.PaymentInfoMapper;
import com.yuma.tingshu.payment.service.PaymentInfoService;
import com.yuma.tingshu.payment.service.TSWxPayService;
import com.yuma.tingshu.user.client.UserInfoFeignClient;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class TSWxPayServiceImpl implements TSWxPayService {

    @Autowired
    private PaymentInfoMapper paymentInfoMapper;
    @Autowired
    private OrderInfoFeignClient orderInfoFeignClient;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;
    @Autowired
    private RechargeInfoFeignClient rechargeInfoFeignClient;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private WxPayProperties wxPayProperties;
    @Autowired
    private PaymentInfoService paymentInfoService;

    //创建微信支付订单
    @Override
    public Object createJsapi(String paymentType, String orderNo) {
        // 1.判空
        if (paymentType == null || orderNo == null) {
            throw new YumaException(ResultCodeEnum.ARGUMENT_VALID_ERROR);
        }
        // 2.获取当前登录用户
        Long userId = AuthContextHolder.getUserId();
        OrderInfo orderInfo = null;
        RechargeInfo rechargeInfo = null;
        // 3.判断订单类型
        if (SystemConstant.PAYMENT_TYPE_ORDER.equals(paymentType)) {
            // 3.1普通订单(vip,专辑，声音)
            //3.1.1 根据订单号获取订单，并判空
            Result<OrderInfo> orderInfoResult = orderInfoFeignClient.getOrderInfo(orderNo);
            Assert.notNull(orderInfoResult, "创建微信支付模块，远程调用查询订单失败");
            orderInfo = orderInfoResult.getData();
            Assert.notNull(orderInfo, "创建微信支付模块，远程调用查询订单失败");
            //3.1.1.1 判断订单是否属于当前用户，不属于当前用户
            if (!orderInfo.getUserId().equals(userId)) {
                throw new YumaException(ResultCodeEnum.ORDER_NOT_BELONG_CURRENT_USER);
            }
            //3.1.1.2 判断此订单是否已支付0902(不能重复支付)
            if (SystemConstant.ORDER_STATUS_PAID.equals(orderInfo.getOrderStatus())) {
                throw new YumaException(ResultCodeEnum.ORDER_PAY_REPEAT);
            }
        } else if (SystemConstant.PAYMENT_TYPE_RECHARGE.equals(paymentType)) {
            // 3.2充值订单
            // 3.2.1 根据订单号获取充值订单
            Result<RechargeInfo> rechargeInfoResult = rechargeInfoFeignClient.getRechargeInfo(orderNo);
            Assert.notNull(rechargeInfoResult, "创建充值微信支付模块，远程调用查询充值订单失败");
            rechargeInfo = rechargeInfoResult.getData();
            Assert.notNull(rechargeInfo, "创建充值微信支付模块，远程调用查询充值订单失败");
            // 3.2.2.1判断该订单是否属于当前用户，不属于当前用户抛异常
            if (!rechargeInfo.getUserId().equals(userId)) {
                throw new YumaException(ResultCodeEnum.ORDER_NOT_BELONG_CURRENT_USER);
            }
            // 3.2.2.2判断此订单状态是否已支付0902(不能重复支付)
            if (SystemConstant.ORDER_STATUS_PAID.equals(rechargeInfo.getRechargeStatus())) {
                throw new YumaException(ResultCodeEnum.ORDER_PAY_REPEAT);
            }
        }
        try {
            /**
             * arg0：微信支付类型APP,JSAPI,NATIVE,H5   实际使用JSAPI面试时候一定要说APP,H5
             * arg1：WxPayUnified0rderV3Request，请求对象
             */
            // 4.请求发起预支付
            WxPayUnifiedOrderV3Result.JsapiResult response = wxPayService.createOrderV3(TradeTypeEnum.JSAPI, createRequestObject(paymentType, orderNo));
            // 5.保存对账记录payment_info表写一条
            PaymentInfo paymentInfo = new PaymentInfo();
            // 如果是订单业务，走OrderInfo对象
            if (SystemConstant.PAYMENT_TYPE_ORDER.equals(paymentType)) {
                paymentInfo.setUserId(userId);
                paymentInfo.setOrderNo(orderInfo.getOrderNo());
                paymentInfo.setAmount(orderInfo.getOrderAmount());
                paymentInfo.setContent(orderInfo.getOrderTitle());
            } else if (SystemConstant.PAYMENT_TYPE_RECHARGE.equals(paymentType)) {
                // 充值业务：RechargeInfo
                paymentInfo.setUserId(rechargeInfo.getUserId());
                paymentInfo.setOrderNo(rechargeInfo.getOrderNo());
                paymentInfo.setAmount(rechargeInfo.getRechargeAmount());
                paymentInfo.setContent("充值");
            }
            paymentInfo.setPaymentType(paymentType);
            paymentInfo.setPayWay(SystemConstant.ORDER_PAY_WAY_WEIXIN);
            paymentInfo.setPaymentStatus(SystemConstant.PAYMENT_STATUS_UNPAID);
            this.paymentInfoMapper.insert(paymentInfo);

            // 6.返回结果封装一个对象Map<String,Object>(签名....)
            Map<String, Object> result = new HashMap<>();
            result.put("timeStamp", response.getTimeStamp());
            result.put("nonceStr", response.getNonceStr());
            result.put("package", response.getPackageValue());
            result.put("signType", response.getSignType());
            result.put("paySign", response.getPaySign());// 签名(当我们支付的时候需要验签(request对象创建的签名))
            result.put("code", WxPayConstants.WxpayTradeStatus.SUCCESS);
            // 7.返回此对象 请求微信支付 -> notifyUrl方法
            return result;
        } catch (WxPayException wxPayException) {
            throw new YumaException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR);
        }
    }

    // 创建请求对象
    private WxPayUnifiedOrderV3Request createRequestObject(String paymentType, String orderNo) {
        WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request();
        request.setAppid(wxPayProperties.getAppId());//appId
        request.setMchid(wxPayProperties.getMchId());//mchId
        if (SystemConstant.PAYMENT_TYPE_ORDER.equals(paymentType)) {
            Result<OrderInfo> orderInfoResult = orderInfoFeignClient.getOrderInfo(orderNo);
            OrderInfo orderInfo = orderInfoResult.getData();
            request.setDescription(orderInfo.getOrderTitle());
        } else if (SystemConstant.PAYMENT_TYPE_RECHARGE.equals(paymentType)) {
            request.setDescription("账户充值");
        }
        request.setOutTradeNo(orderNo);
        request.setNotifyUrl(wxPayProperties.getNotifyUrl());
        request.setGoodsTag(SystemConstant.PAYMENT_TYPE_ORDER.equals(paymentType) ? "订单业务" : "充值订单");
        request.setSupportFapiao(false);
        // 设置支付金额
        WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount();
        amount.setTotal(1);  // 测试使用1分钱
        amount.setCurrency(WxPayConstants.CurrencyType.CNY);  //货币类型
        request.setAmount(amount);
        // 设置支付用户 wxOpenId需要从数据库里查询
        WxPayUnifiedOrderV3Request.Payer payer = new WxPayUnifiedOrderV3Request.Payer();
        Long userId = AuthContextHolder.getUserId();
        Result<UserInfo> userResult = userInfoFeignClient.getUserById(userId);
        Assert.notNull(userResult, "生成支付页面，获取用户详情失败");
        payer.setOpenid(userResult.getData().getWxOpenId());  // 用户openId
        request.setPayer(payer);
        // 设置过期时间 yyyy-MM-dd'T'HH:mm:ss+TIMEZONE   订单20分钟后在微信服务器端过期
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
        request.setTimeExpire(dateFormat.format(DateUtil.offset(new Date(), DateField.MINUTE, 20)));
        return request;
    }

    // 微信回调
    @Override
    public ResponseEntity payCallback(Map body, HttpServletRequest request) {
        try {
            // 1.body 微信服务器返回的整个响应体->String
            ObjectMapper objectMapper = new ObjectMapper();
            String data = objectMapper.writeValueAsString(body);
            // 2.验签
            // 选择notify的签名头
            SignatureHeader header = new SignatureHeader();
            header.setTimeStamp(request.getHeader("Wechatpay-Timestamp"));
            header.setNonce(request.getHeader("Wechatpay-Nonce"));
            header.setSignature(request.getHeader("Wechatpay-Signature"));
            header.setSerial(request.getHeader("Wechatpay-Serial"));
            // 3.解析支付返回的数据
            WxPayNotifyV3Result wxPayNotifyV3Result = wxPayService.parseOrderNotifyV3Result(data, header);
            WxPayNotifyV3Result.DecryptNotifyResult result = wxPayNotifyV3Result.getResult();
            if (WxPayConstants.WxpayTradeStatus.SUCCESS.equals(result.getTradeState())) {
                // 3.1如果返回中支付成功码，就去更新paymentInfo状态，从1401未支付 -> 1402已支付
                // 更新payment状态和回调
                paymentInfoService.updatePaymentStatus(result);// 在内部实现orderInfo状态也修改，从0901未支付 -> 0902已支付
                // 返回ResponseEntity成功
                return ResponseEntity.status(HttpStatus.OK).build();
            } else {
                // 3.2失败后抛出HttpStatus状态异常
                return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
        }
    }

    // 查询支付状态
    @Override
    public Boolean queryPayStatus(String orderNo) {
        // 1.根据orderNo查询payment对象
        PaymentInfo paymentInfo = paymentInfoService.getOne(new LambdaQueryWrapper<PaymentInfo>()
                .eq(PaymentInfo::getOrderNo, orderNo));
        // 2.支付详情不为空 并且 支付状态是成功
        return paymentInfo != null && paymentInfo.getPaymentStatus().equals(SystemConstant.PAYMENT_STATUS_PAID);
    }
}
